home *** CD-ROM | disk | FTP | other *** search
- //: C26:MemCheck.cpp {O}
- // From Thinking in C++, 2nd Edition
- // Available at http://www.BruceEckel.com
- // (c) Bruce Eckel 1999
- // Copyright notice in Copyright.txt
- // Memory allocation tester
- #include <cstdlib>
- #include <cstring>
- #include <cstdio>
- using namespace std;
- // MemCheck.h must not be included here
-
- // Output file object using cstdio
- // (cout constructor calls malloc())
- class OFile {
- FILE* f;
- public:
- OFile(char* name) : f(fopen(name, "w")) {}
- ~OFile() { fclose(f); }
- operator FILE*() { return f; }
- };
- extern OFile memtrace;
- // Comment out the following to send all the
- // information to the trace file:
- #define memtrace stdout
-
- const unsigned long _pool_sz = 50000L;
- static unsigned char _memory_pool[_pool_sz];
- static unsigned char* _pool_ptr = _memory_pool;
-
- void* getmem(size_t sz) {
- if(_memory_pool + _pool_sz - _pool_ptr < sz) {
- fprintf(stderr,
- "Out of memory. Use bigger model\n");
- exit(1);
- }
- void* p = _pool_ptr;
- _pool_ptr += sz;
- return p;
- }
-
- // Holds information about allocated pointers:
- class MemBag {
- public:
- enum type { Malloc, New };
- private:
- char* typestr(type t) {
- switch(t) {
- case Malloc: return "malloc";
- case New: return "new";
- default: return "?unknown?";
- }
- }
- struct M {
- void* mp; // Memory pointer
- type t; // Allocation type
- char* file; // File name where allocated
- int line; // Line number where allocated
- M(void* v, type tt, char* f, int l)
- : mp(v), t(tt), file(f), line(l) {}
- }* v;
- int sz, next;
- static const int increment = 50 ;
- public:
- MemBag() : v(0), sz(0), next(0) {}
- void* add(void* p, type tt = Malloc,
- char* s = "library", int l = 0) {
- if(next >= sz) {
- sz += increment;
- // This memory is never freed, so it
- // doesn't "get involved" in the test:
- const int memsize = sz * sizeof(M);
- // Equivalent of realloc, no registration:
- void* p = getmem(memsize);
- if(v) memmove(p, v, memsize);
- v = (M*)p;
- memset(&v[next], 0,
- increment * sizeof(M));
- }
- v[next++] = M(p, tt, s, l);
- return p;
- }
- // Print information about allocation:
- void allocation(int i) {
- fprintf(memtrace, "pointer %p"
- " allocated with %s",
- v[i].mp, typestr(v[i].t));
- if(v[i].t == New)
- fprintf(memtrace, " at %s: %d",
- v[i].file, v[i].line);
- fprintf(memtrace, "\n");
- }
- void validate(void* p, type T = Malloc) {
- for(int i = 0; i < next; i++)
- if(v[i].mp == p) {
- if(v[i].t != T) {
- allocation(i);
- fprintf(memtrace,
- "\t was released as if it were "
- "allocated with %s \n", typestr(T));
- }
- v[i].mp = 0; // Erase it
- return;
- }
- fprintf(memtrace,
- "pointer not in memory list: %p\n", p);
- }
- ~MemBag() {
- for(int i = 0; i < next; i++)
- if(v[i].mp != 0) {
- fprintf(memtrace,
- "pointer not released: ");
- allocation(i);
- }
- }
- };
- extern MemBag MEMBAG_;
-
- void* malloc(size_t sz) {
- void* p = getmem(sz);
- return MEMBAG_.add(p, MemBag::Malloc);
- }
-
- void* calloc(size_t num_elems, size_t elem_sz) {
- void* p = getmem(num_elems * elem_sz);
- memset(p, 0, num_elems * elem_sz);
- return MEMBAG_.add(p, MemBag::Malloc);
- }
-
- void* realloc(void* block, size_t sz) {
- void* p = getmem(sz);
- if(block) memmove(p, block, sz);
- return MEMBAG_.add(p, MemBag::Malloc);
- }
-
- void free(void* v) {
- MEMBAG_.validate(v, MemBag::Malloc);
- }
-
- void* operator new(size_t sz) {
- void* p = getmem(sz);
- return MEMBAG_.add(p, MemBag::New);
- }
-
- void*
- operator new(size_t sz, char* file, int line) {
- void* p = getmem(sz);
- return MEMBAG_.add(p, MemBag::New, file,line);
- }
-
- void operator delete(void* v) {
- MEMBAG_.validate(v, MemBag::New);
- }
-
- MemBag MEMBAG_;
- // Placed here so the constructor is called
- // AFTER that of MEMBAG_ :
- #ifdef memtrace
- #undef memtrace
- #endif
- OFile memtrace("memtrace.out");
- // Causes 1 "pointer not in memory list" message
- ///:~
-